package com.gitee.zhuyb.refresh.chart;

import com.sun.org.apache.regexp.internal.RE;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.XWPFChart;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.openxmlformats.schemas.drawingml.x2006.chart.*;

import java.io.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @version 1.0.0
 * @Description: 从指定word模板获取雷达图图表,然后动态刷新数据
 * @Date: 2021/12/26 11:55
 * @Copyright (C) ZhuYouBin
 */
public class RadarChart {

    private static final String RESULT = "H:\\poi\\radarChart_zhuyb.docx";
    private static final String TEMPLATE = "G:\\zhuyoubin_gitee_space\\code\\work-demo\\poi-word\\src\\main\\resources\\多图word模板.docx";
//    private static final String TEMPLATE = "G:\\zhuyoubin_gitee_space\\code\\work-demo\\poi-word\\src\\main\\resources\\雷达图.docx";

    public static void main(String[] args) throws Exception {
        // 1、读取word模板文件
        InputStream is = new FileInputStream(new File(TEMPLATE));
        // 2、创建word文档对象
        XWPFDocument document = new XWPFDocument(is);

        // 3、获取word中的图表对象
//        List<XWPFChart> charts = document.getCharts();
//        System.out.println(charts.size());
//
//        for (XWPFChart chart : charts) {
//            System.out.println("-->>:"+chart.toString());
//        }

        // 获取所有word图表对象
        List<POIXMLDocumentPart> chartRelation = document.getRelations();
        // 遍历chart图表
        Map<String, POIXMLDocumentPart> chartMap = new HashMap<String, POIXMLDocumentPart>();
        for (POIXMLDocumentPart chartPart : chartRelation) {
            // 判断是否为chart图表对象
            if (chartPart instanceof XWPFChart) {
                // 处理key值,这里采用chartPart对象的toString()的值
                /*
                chartPart.toString()的值格式如下所示:
                Name: /word/charts/chart1.xml - Content Type: application/vnd.openxmlformats-officedocument.drawingml.chart+xml
                Name: /word/charts/chart2.xml - Content Type: application/vnd.openxmlformats-officedocument.drawingml.chart+xml
                Name: /word/charts/chart3.xml - Content Type: application/vnd.openxmlformats-officedocument.drawingml.chart+xml
                多个chart对象,只有 chart1.xml、chart2.xml、chart3.xml 不同,其余内容都是一样的
                所以,这里通过获取 /word/charts/chart1.xml 作为map的key值
                 */
                String chartStr = chartPart.toString();
                chartStr = chartStr.replaceAll("Name:", "")
                        .replaceAll("- Content Type: application/vnd\\.openxmlformats-officedocument\\.drawingml\\.chart\\+xml", "");
                String key = chartStr.trim();
                // 是图表对象,则保存到map容器
                chartMap.put(key, chartPart);
            }
        }
        System.out.println("图表集合: \n" + chartMap);

        // TODO 准备图表数据
        // (1)第一个图表数据
        // X轴分类
        List<String> xAxisTitle = new ArrayList<>();
        xAxisTitle.add(""); // 第一列空着,目的是为了存放Y轴分类
        xAxisTitle.add("粉丝数(个)");

        // Y轴分类
        List<String> yAxisTitle = new ArrayList<>();
        yAxisTitle.add("yItem01");
        yAxisTitle.add("yItem02");

        // 数据集
        List<Map<String, String>> dataMapList = new ArrayList<>();

        // 第一行
        Map<String, String> row1 = new HashMap<>();
        row1.put(yAxisTitle.get(0), "2021-12");
        row1.put(yAxisTitle.get(1), 35+"");

        Map<String, String> row2 = new HashMap<>();
        row2.put(yAxisTitle.get(0), "2021-11");
        row2.put(yAxisTitle.get(1), 53+"");

        Map<String, String> row3 = new HashMap<>();
        row3.put(yAxisTitle.get(0), "2021-10");
        row3.put(yAxisTitle.get(1), 27+"");

        Map<String, String> row4 = new HashMap<>();
        row4.put(yAxisTitle.get(0), "2021-09");
        row4.put(yAxisTitle.get(1), 68+"");

        Map<String, String> row5 = new HashMap<>();
        row5.put(yAxisTitle.get(0), "2021-08");
        row5.put(yAxisTitle.get(1), 17+"");

        dataMapList.add(row1);
        dataMapList.add(row2);
        dataMapList.add(row3);
        dataMapList.add(row4);
        dataMapList.add(row5);

        // 替换雷达图图表数据
        POIXMLDocumentPart chart1 = chartMap.get("/word/charts/chart1.xml");

        // TODO 雷达图图表
        XWPFChart chart01 = (XWPFChart) chart1;

        // 获取图表对应的XML
        CTChart ctChart = chart01.getCTChart();
        System.out.println(ctChart);
        CTPlotArea plotArea = ctChart.getPlotArea();

        CTRadarChart radarChart = plotArea.getRadarChartArray(0);
        System.out.println("****>:\n"+radarChart);

        //
        List<CTRadarSer> serList = radarChart.getSerList();
        System.out.println("==>:\n"+serList);

        // TODO 刷新雷达图对应的excel表格数据
        // 其实就是创建一个最新的excel数据表格,然后替换旧的数据表格
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("Sheet1");
        // 创建表格第一行标头
        for (int i = 0; i < xAxisTitle.size(); i++) {
            // 获取excel表格第一行
            Row row = sheet.getRow(0);
            if (row == null) {
                // 如果不存在第一行,则创建第一行
                sheet.createRow(0)
                        .createCell(i)
                        .setCellValue(xAxisTitle.get(i) == null ? "" : xAxisTitle.get(i));
            } else {
                // 如果存在第一行,则替换第一行内容
                sheet.getRow(0)
                        .createCell(i)
                        .setCellValue(xAxisTitle.get(i) == null ? "" : xAxisTitle.get(i));
            }
        }

        // 从第二行开始,遍历数据
        for (int i = 0; i < dataMapList.size(); i++) {
            // 需要填充的数据行
            Map<String, String> dataMap = dataMapList.get(i);
            // 遍历
            for (int j = 0; j < yAxisTitle.size(); j++) {
                // 从第二行开始
                Row currentRow = sheet.getRow(i + 1);
                // 列值
                String cellValue = dataMap.get(yAxisTitle.get(j));
                if (currentRow == null) {
                    // 如果不存在,则创建新行
                    if (j == 0) {
                        sheet.createRow(i+1)
                                .createCell(j)
                                .setCellValue(cellValue == null ? "" : cellValue);
                    }
                } else {
                    // 如果存在,则覆盖旧行数据
                    BigDecimal decimal = new BigDecimal(cellValue);
                    // 设置值
                    currentRow.createCell(j).setCellValue(decimal.doubleValue());
                }
            }
        }

        // 更新图表中嵌入的excel数据表格
        POIXMLDocumentPart excelPart = chart01.getRelations().get(0);
        OutputStream excelOut = excelPart.getPackagePart().getOutputStream();
        try {
            // 输出流
            workbook.write(excelOut);
            // 关闭excel流
            excelOut.close();
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            // 关闭sheet
            if (workbook != null) {
                try {
                    workbook.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        // TODO 刷新雷达图数据
        for (int i = 0; i < serList.size(); i++) {
            //
            CTRadarSer serArray = radarChart.getSerArray(i);
            CTAxDataSource catDataSource = serArray.getCat();
            CTNumDataSource valDataSource = serArray.getVal();
            // 标题
            // 设置标题 用以下这个方式，可以兼容office和wps
            CTSerTx title = serArray.getTx();
            // tx.getStrRef().getStrCache().getPtList().get(0).setV("嘿嘿嘿");

            // 清空并且重置数据
            if (null != catDataSource.getNumRef()) {
                catDataSource.unsetNumRef();
            }
            if (null !=catDataSource.getStrRef()) {
                catDataSource.unsetStrRef();
            }
            catDataSource.addNewStrRef().addNewStrCache();

            CTStrData strCache = catDataSource.getStrRef().getStrCache();
            strCache.setPtArray(null);
            CTNumData numCache = valDataSource.getNumRef().getNumCache();
            numCache.setPtArray(null);

            // 开始设置新数据
            long index = 0;
            for (int j = 0; j < dataMapList.size(); j++) {
                Map<String, String> dataMap = dataMapList.get(j);
                String value = "0";
                BigDecimal decimal = new BigDecimal(dataMap.get(yAxisTitle.get(i + 1)));
                if (decimal != null) {
                    value = decimal.toString();
                }
                if (!"0".equals(value)) {
                    CTNumVal numVal = numCache.addNewPt();
                    numVal.setIdx(index);
                    numVal.setV(value);
                }
                CTStrVal strVal = strCache.addNewPt();
                strVal.setIdx(index);
                strVal.setV(value);
                index++;
            }
            strCache.addNewPtCount().setVal(index);
            numCache.getPtCount().setVal(index);

            // 赋值横坐标数据
            String axisDataRange = new CellRangeAddress(1, dataMapList.size(), 0, 0)
                    .formatAsString("Sheet1", true);
            catDataSource.getStrRef().setF(axisDataRange);

            // 数据区域
            String numDataRange = new CellRangeAddress(1, dataMapList.size(), i + 1, i + 1)
                    .formatAsString("Sheet1", true);
            valDataSource.getNumRef().setF(numDataRange);
        }



        // (2)第二个图表数据

        // 输出新的word文档
        try {
            File file = new File(RESULT);
            if (file.exists()) {
                file.delete();
            }
            FileOutputStream fos = new FileOutputStream(RESULT);
            document.write(fos);
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 关闭流
        document.close();
    }


}
